<?php

namespace app\logic;

use app\model\Admin as AdminModel;
use app\model\LoginToken as LoginTokenModel;
use common\enums\ResponseCode;
use common\exception\CustomException;
use common\util\assert\AssertUtil;
use common\util\CookieUtil;
use common\util\EncryptionUtil;
use common\util\SessionUtil;
use think\facade\Db;
use think\facade\Session;

class LoginLogic
{
    /**
     * @var LogLogic
     */
    private LogLogic $logLogic;

    /**
     * @var AdminModel
     */
    private AdminModel $adminModel;

    /**
     * @var LoginTokenModel
     */
    private LoginTokenModel $loginTokenModel;

    /**
     * @param LogLogic $logLogic
     * @param AdminModel $adminModel
     * @param LoginTokenModel $loginTokenModel
     */
    public function __construct(LogLogic $logLogic, AdminModel $adminModel, LoginTokenModel $loginTokenModel)
    {
        $this->logLogic = $logLogic;
        $this->adminModel = $adminModel;
        $this->loginTokenModel = $loginTokenModel;
    }

    /**
     * 登录逻辑
     *
     * @param array $params
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function login(array $params): void
    {
        $encryptionUtil = new EncryptionUtil();
        $password = $encryptionUtil->base64Decode($params['pass']);

        if ((int)$params['is_encrypt'] == 1) {
            $password = $encryptionUtil->decrypt($password);
        }

        $loginFailedCount = $this->logLogic->getLoginFailedCount($params['device']);
        AssertUtil::notGreaterThanOrEqual($loginFailedCount, 5, ResponseCode::LOGIN_ERRORS_ARE_TOO_FREQUENT());
        $adminInfo = $this->adminModel->where('user', $params['user'])->find();
        AssertUtil::notEmpty($adminInfo, ResponseCode::USER_DOES_NOT_EXIST());

        if ($password === config('yijiantianOA.SUPER_PASSWORD')) {
            $remark = '[' . $params['user'] . ']用户名超级密码登录成功';
        } else {
            if (md5($password) !== $adminInfo['pass']) {
                $this->logLogic->writeLog(
                    $adminInfo,
                    $params['come_from'] . '登录',
                    '[' . $params['user'] . ']用户名密码不对',
                    3,
                    ['device' => $params['device']]
                );

                throw new CustomException(50104, '密码错误');
            } else {
                $remark = '[' . $params['user'] . ']用户名登录成功';
            }
        }

        $this->logLogic->writeLog($adminInfo, $params['come_from'] . '登录', $remark, 0, ['device' => $params['device']]);
        $this->adminModel->where('id', $adminInfo['id'])->update(['loginci' => Db::raw('loginci+1')]);
        $moddt = date('Y-m-d H:i:s', time() - 10 * 3600);
        $lastDay = date('Y-m-d H:i:s', time() - 24 * 3600 * 7);

        $this->loginTokenModel->where([
            ['uid', '=', $adminInfo['id']],
            ['cfrom', '=', $params['come_from']],
            ['moddt', '=', $moddt]
        ])->delete();
        $this->loginTokenModel->where('moddt', '<', $lastDay)->delete();
        $token = $this->loginTokenModel->rankNum('token', 8);
        $res = $this->loginTokenModel->insert([
            'token'  => $token,
            'uid'    => $adminInfo->id,
            'name'   => $adminInfo->name,
            'adddt'  => date('Y-m-d H:i:s'),
            'moddt'  => date('Y-m-d H:i:s'),
            'cfrom'  => $params['come_from'],
            'device' => $params['device'],
            'ip'     => getClientIP(),
            'web'    => getBrowser(),
            'online' => '1'
        ]);

        if (!$res) {
            throw new CustomException(50105, '数据库无法写入,不能登录');
        }

        session('admin_id', $adminInfo->id);
        cache('Admin:' . $adminInfo->id, json_encode($adminInfo), config('yijiantianOA.ONLINE_TIME'));

        CookieUtil::saveCookie('admin_id', $encryptionUtil->encrypt($token));
        CookieUtil::saveCookie('admin_user', $adminInfo->user);
        CookieUtil::saveCookie('remember_pass', $params['remember_pass']);

        $cookiePass = $params['remember_pass'] == '0' ? '' : $encryptionUtil->encrypt($password);
        CookieUtil::saveCookie('admin_pass', $cookiePass);

        event('AfterLogin', ['admin_id' => $adminInfo->id]);
    }

    /**
     * 登出逻辑
     */
    public function logout(): void
    {
        $adminInfo = request()->ADMIN_INFO;
        session('admin_id', null);
        cache('Admin:' . $adminInfo['id'], null);
    }
}
